package jk

import (
	"fmt"
	"net/http"
	"slices"
	"strings"

	"gitee.com/ruige_fun/rht"
)

type Context interface {
	rht.HttpServerContextFunc
}

func NewServeMux() Serve {
	return &serveMux{
		defaultMux: http.NewServeMux(),
		allRouters: new([]routeStrItem),
	}
}

type Serve interface {
	// Use 中间件
	Use(fx MiddlewareFunc) Serve
	// Group 分组，自动往请求路径前面增加prevPath
	Group(prevPath string) Serve
	// Handler 响应处理
	Handler(pattern string, handler http.Handler, description ...string)
	// HandleFunc 处理函数
	HandleFunc(pattern string, handler HandlerFunc, description ...string)
	// HandleFuncN 处理函数
	HandleFuncN(pattern string, handler HandlerFuncNotErr, description ...string)

	// Get 常用路由注册方法
	Get(pattern string, handler HandlerFunc, description ...string)
	// Post 常用路由注册方法
	Post(pattern string, handler HandlerFunc, description ...string)
	// Put 常用路由注册方法
	Put(pattern string, handler HandlerFunc, description ...string)
	// Delete 常用路由注册方法
	Delete(pattern string, handler HandlerFunc, description ...string)
	// Patch 常用路由注册方法
	Patch(pattern string, handler HandlerFunc, description ...string)
	// Options 常用路由注册方法
	Options(pattern string, handler HandlerFunc, description ...string)
	// Head 常用路由注册方法
	Head(pattern string, handler HandlerFunc, description ...string)
	// Connect 常用路由注册方法
	Connect(pattern string, handler HandlerFunc, description ...string)
	// Trace 常用路由注册方法
	Trace(pattern string, handler HandlerFunc, description ...string)
	// GetN 常用路由注册方法
	GetN(pattern string, handler HandlerFuncNotErr, description ...string)
	// PostN 常用路由注册方法
	PostN(pattern string, handler HandlerFuncNotErr, description ...string)
	// PutN 常用路由注册方法
	PutN(pattern string, handler HandlerFuncNotErr, description ...string)
	// DeleteN 常用路由注册方法
	DeleteN(pattern string, handler HandlerFuncNotErr, description ...string)
	// PatchN 常用路由注册方法
	PatchN(pattern string, handler HandlerFuncNotErr, description ...string)
	// OptionsN 常用路由注册方法
	OptionsN(pattern string, handler HandlerFuncNotErr, description ...string)
	// HeadN 常用路由注册方法
	HeadN(pattern string, handler HandlerFuncNotErr, description ...string)
	// ConnectN 常用路由注册方法
	ConnectN(pattern string, handler HandlerFuncNotErr, description ...string)
	// TraceN 常用路由注册方法
	TraceN(pattern string, handler HandlerFuncNotErr, description ...string)

	// ServeHTTP http服务
	ServeHTTP(w http.ResponseWriter, r *http.Request)
	// AllRouters 返回所有已注册的路由地址
	AllRouters() []routeStrItem
}
type MiddlewareFunc func(HandlerFunc) HandlerFunc

func (m MiddlewareFunc) Append(fx MiddlewareFunc) MiddlewareFunc {
	return func(h HandlerFunc) HandlerFunc {
		return m(fx(h))
	}
}

type HandlerFunc func(Context) Error
type HandlerFuncNotErr func(Context)

type routeStrItem struct {
	Path        string
	Description string
}

func (r routeStrItem) String() string {
	return fmt.Sprintf("%s\t//%s", r.Path, r.Description)
}

type serveMux struct {
	defaultMux *http.ServeMux
	middleware MiddlewareFunc
	prevPath   []string
	allRouters *[]routeStrItem
}

func (s *serveMux) AllRouters() []routeStrItem {
	return *s.allRouters
}

func (s *serveMux) Group(prevPath string) Serve {
	return &serveMux{
		defaultMux: s.defaultMux,
		middleware: s.middleware,
		prevPath:   append(s.prevPath, prevPath),
		allRouters: s.allRouters,
	}
}

func (s *serveMux) Use(fx MiddlewareFunc) Serve {
	result := &serveMux{
		defaultMux: s.defaultMux,
		prevPath:   slices.Clone(s.prevPath),
		allRouters: s.allRouters,
	}
	if s.middleware == nil {
		result.middleware = fx
	} else {
		result.middleware = s.middleware.Append(fx)
	}
	return result
}

func (s *serveMux) handlerPattern(pattern string) string {
	pattern = strings.TrimSpace(pattern)
	before, after, found := strings.Cut(pattern, " ")
	if found {
		pattern = before + " " + strings.Join(s.prevPath, "/") + after
	} else {
		pattern = strings.Join(s.prevPath, "/") + pattern
	}
	for strings.Contains(pattern, "//") || strings.Contains(pattern, `\\`) {
		pattern = strings.ReplaceAll(pattern, "//", "/")
		pattern = strings.ReplaceAll(pattern, `\\`, `\`)
	}
	return pattern
}

func (s *serveMux) Handler(pattern string, handler http.Handler, description ...string) {
	jkHandler := func(c Context) Error {
		handler.ServeHTTP(c.Response(), c.Request().Request())
		return nil
	}
	s.HandleFunc(pattern, jkHandler, description...)
}

func (s *serveMux) HandleFunc(pattern string, handler HandlerFunc, description ...string) {
	pattern = s.handlerPattern(pattern)
	*s.allRouters = append(*s.allRouters, routeStrItem{
		Path:        pattern,
		Description: strings.Join(description, "；"),
	})
	s.defaultMux.HandleFunc(pattern, func() http.HandlerFunc {
		return func(writer http.ResponseWriter, request *http.Request) {
			ctx := rht.NewHttpServerContext(writer, request)
			var err Error
			if s.middleware != nil {
				err = s.middleware(handler)(ctx)
			} else {
				err = handler(ctx)
			}
			if err != nil {
				if ctx.Response().StatusCode() == 200 && err.GetStatusCode() != 200 {
					ctx.Response().WriteStatusCode(err.GetStatusCode())
				}
				_ = ctx.Response().WriteStdJSON(err.GetCode(), err.GetMsg(), nil, nil)
			}
		}
	}())
}

func (s *serveMux) HandleFuncN(pattern string, handler HandlerFuncNotErr, description ...string) {
	s.HandleFunc(pattern, func(c Context) Error {
		handler(c)
		return nil
	}, description...)
}

func (s *serveMux) Get(pattern string, handler HandlerFunc, description ...string) {
	s.HandleFunc(http.MethodGet+" "+pattern, handler, description...)
}

func (s *serveMux) Post(pattern string, handler HandlerFunc, description ...string) {
	s.HandleFunc(http.MethodPost+" "+pattern, handler, description...)
}

func (s *serveMux) Put(pattern string, handler HandlerFunc, description ...string) {
	s.HandleFunc(http.MethodPut+" "+pattern, handler, description...)
}

func (s *serveMux) Delete(pattern string, handler HandlerFunc, description ...string) {
	s.HandleFunc(http.MethodDelete+" "+pattern, handler, description...)
}

func (s *serveMux) Patch(pattern string, handler HandlerFunc, description ...string) {
	s.HandleFunc(http.MethodPatch+" "+pattern, handler, description...)
}

func (s *serveMux) Options(pattern string, handler HandlerFunc, description ...string) {
	s.HandleFunc(http.MethodOptions+" "+pattern, handler, description...)
}

func (s *serveMux) Head(pattern string, handler HandlerFunc, description ...string) {
	s.HandleFunc(http.MethodHead+" "+pattern, handler, description...)
}

func (s *serveMux) Connect(pattern string, handler HandlerFunc, description ...string) {
	s.HandleFunc(http.MethodConnect+" "+pattern, handler, description...)
}

func (s *serveMux) Trace(pattern string, handler HandlerFunc, description ...string) {
	s.HandleFunc(http.MethodTrace+" "+pattern, handler, description...)
}

func (s *serveMux) GetN(pattern string, handler HandlerFuncNotErr, description ...string) {
	s.HandleFuncN(http.MethodGet+" "+pattern, handler, description...)
}

func (s *serveMux) PostN(pattern string, handler HandlerFuncNotErr, description ...string) {
	s.HandleFuncN(http.MethodPost+" "+pattern, handler, description...)
}

func (s *serveMux) PutN(pattern string, handler HandlerFuncNotErr, description ...string) {
	s.HandleFuncN(http.MethodPut+" "+pattern, handler, description...)
}

func (s *serveMux) DeleteN(pattern string, handler HandlerFuncNotErr, description ...string) {
	s.HandleFuncN(http.MethodDelete+" "+pattern, handler, description...)
}

func (s *serveMux) PatchN(pattern string, handler HandlerFuncNotErr, description ...string) {
	s.HandleFuncN(http.MethodPatch+" "+pattern, handler, description...)
}

func (s *serveMux) OptionsN(pattern string, handler HandlerFuncNotErr, description ...string) {
	s.HandleFuncN(http.MethodOptions+" "+pattern, handler, description...)
}

func (s *serveMux) HeadN(pattern string, handler HandlerFuncNotErr, description ...string) {
	s.HandleFuncN(http.MethodHead+" "+pattern, handler, description...)
}

func (s *serveMux) ConnectN(pattern string, handler HandlerFuncNotErr, description ...string) {
	s.HandleFuncN(http.MethodConnect+" "+pattern, handler, description...)
}
func (s *serveMux) TraceN(pattern string, handler HandlerFuncNotErr, description ...string) {
	s.HandleFuncN(http.MethodTrace+" "+pattern, handler, description...)
}

func (s *serveMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	s.defaultMux.ServeHTTP(w, r)
}
